iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0

前言


學以致用,把主畫面組裝起來。
https://ithelp.ithome.com.tw/upload/images/20221002/20136048x6up2Whbsg.png

MainScreen

這裡傳三個 funtion 用來做頁面轉換用。

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(
    onSearchBarClick: () -> Unit,
    onAddTrainingClick: () -> Unit,
    onTrainingClick: (Long) -> Unit,
) {

}
  • onSearchBarClick 搜尋欄被點擊時,要跳轉頁面。
  • onAddTrainingClick 新增事件時,要跳轉頁面。
  • onTrainingClick 當事件被點擊時,要跳轉頁面,並且戴上 Training 的 id 值

Scaffold

利用 Scaffold 來佈局畫面。

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(
   //...
) {
		Scaffold(
        topBar = {//... },
        floatingActionButton = {//...}
    ) { padding -> //... }
}
  • topBar 放搜尋欄
  • floatingActionButton 新增事件的懸浮按鈕
  • padding 自動算好扣除 topBarpadding 距離。帶入最外層的 composable modifier.padding 就可以用了

TopAppBar

搜尋欄位

TopAppBar(
    modifier = Modifier
        .clickable { onSearchBarClick() }
        .padding(8.dp),
    title = {
        OutlinedTextField(
            modifier = Modifier.fillMaxWidth(),
            value = "",
            onValueChange = {},
            placeholder = {
                Text(text = "搜尋")
            },
            shape = CircleShape
        )
    }
)
  • modifier 設置了clickable 點擊就跳轉頁面,padding上下左右外距8.dp
  • 搜尋欄位用了 OutlinedTextField 呈現placeholder提示字串,並且將外型shape改為原型。因為要跳轉頁面 value 值不特別紀錄,onValueChange也不處理。

floatingActionButton

新增訓練的懸浮按鈕

import androidx.compose.material.icons.filled.Add

floatingActionButton = {
    FloatingActionButton(onClick = { onAddTrainingClick() }) {
        Icon(Icons.Filled.Add, contentDescription = "Add Training")
    }
}

採用 FloatingActionButtononClick lambda 放入 onAddTrainingClick() 來跳轉頁面。Button content 使用 material icon filled 樣式的 add

LazyVerticalGrid

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(
    //...
) {
    Scaffold(
        //...
    ) { padding ->
				//1.check data is not empty
        if (trainingList.isEmpty()) {
            Text(modifier = Modifier.fillMaxSize(), text = "來安排訓練菜單吧!")
        } else {
            LazyVerticalGrid(//...) { //2.
                items(trainingList) { training ->
                    //...
                }
            }
        }
    }
}
  1. 在 Grid Layout 外層先判斷有沒有訓練資料,沒有就顯示字串,有就顯示列表。
  2. LazyVerticalGriditems 傳入 trainingListlambda 就能使用 training 資料。
    training list 目前是寫死了,之後要改寫成用 ViewModel 取值。
{ padding ->
	LazyVerticalGrid(
	    modifier = Modifier
	        .padding(padding)//1.
	        .padding(horizontal = 16.dp),
	    columns = GridCells.Fixed(2),//2.
	    horizontalArrangement = Arrangement.spacedBy(8.dp),
	    verticalArrangement = Arrangement.spacedBy(8.dp),
	) {
	    //...
	}
}
  1. LazyVerticalGrid 是最上層的 composable 帶入 Scaffoldpaddingmodifier 可以扣除 topAppBar 的高。
  2. columns 設置欄位數為 2
  3. horizontalArrangementverticalArrangementspacedBy調整 item 和 item 之間的距離為 8.dp

TrainingCard

TrainingCard 負責呈現一個訓練的卡片資訊

items(trainingList) { training ->
    TrainingCard(
        onCardClick = { id ->
            onTrainingClick(id) //1.
        },
        training = training
    )
}
  1. 點擊時 onTrainingClick 可以轉跳頁面並且帶上 training id

TrainingCard 運用了 Card 、Text 元件還有 Column 來佈局。

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TrainingCard(
    onCardClick: (Long) -> Unit,
    training: Training
) {
    Card(
        onClick = {
            onCardClick(training.id)
        },
    ) {
        Column(
            modifier = Modifier.padding(8.dp)
        ) {
            Card(
                shape = CircleShape,
                colors = CardDefaults.cardColors(containerColor = Color.Gray),
                modifier = Modifier.fillMaxWidth()
            ) {
                Text(
                    text = training.date.format(formatter),
                    style = MaterialTheme.typography.titleMedium,
                    textAlign = TextAlign.Center,
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(4.dp),
                    color = Color.White
                )
            }

            Text(
                text = training.trainingContext,
                style = MaterialTheme.typography.bodyMedium,
                modifier = Modifier.padding(8.dp)
            )
        }
    }
}

日期 formatter

指定日期樣式

val formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd (E)", Locale.TAIWAN)

總結


今天將 main 頁面調整完,還剩下在 navigation 的資料處理,以及將 training list 從 Data 層串到 ViewModel。以及 GridLayout 在左右兩側高度不同時沒有自動適應高度。

今日運動
休息


上一篇
Day 25 Advance State 和 Side Effect
下一篇
Day 27 Training 頁面實作
系列文
今年一定減成功!Jetpack Compose 做出重訓紀錄APP30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言